﻿using IntelLocalVoiceAI.Diagnostics;
using IntelLocalVoiceAI.ResponseData;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using VoiceAI;
using Windows.Storage;
using XiaoWeiOffLineSDK;

namespace IntelLocalVoiceAI
{
    public enum AsrFrontendState
    {
        Read = 0,
        ListeningSilence = 1,
        ListeningSpeech = 2,
        Processing = 3,
        Stopped = 4
    };
    public enum StatusCode
    {
        Success = 0,
        InvalidHandleValue = -6,
        UnknownError = -1
    }
    public class IntelLocalVoiceAI:IVoiceAI
    {
        private OffLineSDK offLineSDK = null;
        public static IntelLocalVoiceAI Instance = new IntelLocalVoiceAI();
        private bool canRecongnise = false;
        private bool isRunning = false;
        public event Action<string> SpeechRecognizing;
        public event Action SpeechRecognizeEnded;
        public event Action<IResponseData> ResponseReceived;

        //public event ConversationEventHandler ProcessEnded;

        private System.Timers.Timer detectTimer = new System.Timers.Timer(1000);
        private System.Timers.Timer recogTimer = new System.Timers.Timer(5000);
        bool isRecogTimeout = false;

        public IntelLocalVoiceAI()
        {
            offLineSDK = new OffLineSDK();
            detectTimer.Enabled = false;
            detectTimer.AutoReset = true;
            detectTimer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
                //Debug.WriteLine("Detect triggered");
                DetectState();
            };

            recogTimer.Enabled = false;
            recogTimer.AutoReset = false;
            recogTimer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
                Debug.WriteLine("Recog timer triggered");
                isRecogTimeout = true;
                StopSpeechRecognize();
            };

        }
        private string defaultRequest = "";
        private string defaultResponse = "";
        private string defaultUrl = "";
        public void SetDefaultTextAndUrl(string request,string response,string url)
        {
            defaultRequest = request;
            defaultResponse = response;
            defaultUrl = url;
        }

        public async Task InitializeAsync()
        {

            await Task.Run(async () =>
            {
                var subFolder = "OffLineGenerateFile";

                var folder = ApplicationData.Current.LocalFolder;
                folder = await folder.CreateFolderAsync(subFolder, CreationCollisionOption.OpenIfExists);
                var localFile = Windows.Storage.ApplicationData.Current.LocalFolder.Path + "\\" + subFolder;
                string path=Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                var configFolder = path+"/OffLineConfigFile/";
                var configfile = path+"/OffLineConfigFile/rh_params.txt";
                int res = offLineSDK.OffLine_RockhopperFSInitialize(configfile, configFolder, localFile);
                if (res != 0)
                {
                    Debug.WriteLine($"OffLine_RockhopperFSInitialize 初始化发生了错误:{res}");
                }
                OffLineSDK.EventUtteranceCallback += OffLine_EventUtteranceCallback;
                res = offLineSDK.OffLine_RockhopperFSSetResultCallback();
                if (res != 0)
                {
                    Debug.WriteLine("offline call back is set error");
                }
                OffLineSDK.FSSetEventCallback += OffLineSDK_FSSetEventCallback; ;
                res = offLineSDK.OffLine_RockhopperFSSetEventCallback();
                if (res != 0)
                {
                    Debug.WriteLine("OffLine RockhopperFSSetEventCallback is initial error");
                }


            }).ConfigureAwait(false);


            //OffLineSDK.EventGeteStatisticsOfAsrEngine += OffLineSDK_EventGeteStatisticsOfAsrEngine;

        }



        public void StartSpeechRecognize()
        {
            canRecongnise = false;
            int ret = offLineSDK.OffLine_RockhopperFSStartEngine();
            if (ret != 0)
            {
                Debug.WriteLine($"offLineSDK.OffLine_RockhopperFSStartEngine error:{ret}");
                return;
            }
            isRunning = true;
            isRecogTimeout = false;
            Debug.WriteLine($"offLineSDK:StartSpeechRecognize");
            recogTimer.Start();
            Task.Run(() => {
                Task.Delay(300);
                DetectState();
                detectTimer.Start();
            });

        }

        public void StopSpeechRecognize()
        {
            if (!isRunning)
            {
                return;
            }
            isRunning = false;
            recogTimer.Stop();
            Task.Run(() =>
            {
                Debug.WriteLine("StopSpeechRecognize start");
                offLineSDK.OffLine_RockhopperFSStopEngine();
                Debug.WriteLine("StopSpeechRecognize end");
            });

        }

        public async Task SendSpeechAudio(byte[] wfst_text)
        {

            await Task.Run(() =>
            {
                OffLine_RockhopperDataType type = OffLine_RockhopperDataType.ROCKHOPPER_DATA_TYPE_SAMPLE_INT_16;
                int ret = offLineSDK.OffLine_RockhopperFSPushData(wfst_text, wfst_text.Length, type);

                Debug.WriteLine($"offline DefaultRockhopperFSPushData ret is {ret}");
            }).ConfigureAwait(false);

        }

        public async Task AbortRequestAsync()
        {
            await Task.Run(() =>
            {
                detectTimer.Stop();
                StopSpeechRecognize();
            }).ConfigureAwait(false);
        }
        private int OffLine_EventUtteranceCallback(object obj, byte[] samples, int nSamples, string UtteranceId, string UtteranceText, float score, int isFinal)
        {
            if (!isRunning || isRecogTimeout)
            {
                Debug.WriteLine("Offline has stoped or timeout, ignore this result");
                return 0;
            }

            Debug.WriteLine($"Offline recognized ,result:{UtteranceText}");
            IResponseData responseData = ResponseCreator.GetResponseData(UtteranceText);
            if(responseData!=null)
            {
                ResponseReceived?.Invoke(responseData);
            }
            else
            {
                ResponseReceived?.Invoke(ResponseCreator.GetDefaultResponse(defaultRequest,defaultResponse,defaultUrl));
            }
            canRecongnise = true;
            recogTimer.Stop();
            detectTimer.Stop();
            SpeechRecognizeEnded?.Invoke();
            return 0;
        }

        private void HandleUnrecognizedCommand()
        {
            Debug.WriteLine("HandleUnrecognizedCommand");

            ResponseReceived?.Invoke(ResponseCreator.GetDefaultResponse(defaultRequest,defaultResponse,defaultUrl));
            SpeechRecognizeEnded?.Invoke();
        }

        private void OffLineSDK_FSSetEventCallback(int eventCode, int value)
        {

            switch (eventCode)
            {
                case 1:
                    Debug.WriteLine("ROCKHOPPER EVENT ON READY FOR SPEECH ");
                    break;
                case 2:

                    Debug.WriteLine("ROCKHOPPER EVENT ON SPEECH BEGIN ");
                    break;
                case 3:
                    Debug.WriteLine("ROCKHOPPER EVENT ON SPEECH END");
                    break;
                case 4:
                    Debug.WriteLine("ROCKHOPPER EVENT ON RMS CHANGED");
                    break;
                case 5:
                    Debug.WriteLine("ROCKHOPPER EVENT ON ERROR");
                    break;
                case 6:
                    Debug.WriteLine("ROCKHOPPER EVENT ENGINE BEGIN");
                    break;
                case 7:
                    if (!canRecongnise && isRecogTimeout)
                    {
                        Debug.WriteLine("ROCKHOPPER EVENT NOT RECOGNIZE ");
                        detectTimer.Stop();
                        HandleUnrecognizedCommand();
                    }
                    Debug.WriteLine("ROCKHOPPER EVENT ENGINE STOPPED ");
                    break;
            }


        }

        private void DetectState()
        {
            int ret = offLineSDK.OffLine_RockhopperFSGetStatistics();

            if (ret == (int)StatusCode.Success)
            {

                SpeechRecognizing?.Invoke("你好，我在听");
            }
            else
            {
                recogTimer.Stop();
                detectTimer.Stop();
                ResponseReceived?.Invoke(ResponseCreator.GetErrorResponse());
                SpeechRecognizeEnded?.Invoke();
                Debug.WriteLine($"offline err happens,{ret}");
            }
        }
    }
}
